package common;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.SortedMap;
import java.util.TreeMap;

import math.LeastSquareMethod;
import math.common.MathCommon;
import math.probability.ExpDistribution;
import math.probability.LNormalDistribution;
import math.probability.LaplasDistribution;
import math.probability.NormalDistribution;
import math.probability.ProbDistribution;
import math.probability.UniformDistribution;

public class SampleTrimming {
	
	private Random r = new Random();
	
	public Map<Double, Double> trimSample (final Map<Double, Double> smpl, final double p) {
		SortedMap<Double, Double> trimmedSmpl = new TreeMap<Double, Double> ();
		trimmedSmpl.putAll(smpl);
		int n = smpl.size();
		int k = (int) Math.round(n*p);
		
		for (int i = 0; i < k; i++ ) {
			trimmedSmpl.remove(trimmedSmpl.firstKey());
			trimmedSmpl.remove(trimmedSmpl.lastKey());
		
		}
		return trimmedSmpl;
	}
	
	public Map<Double, Double> trimSample1 (final Map<Double, Double> smpl, final double p) {
		SortedMap<Double, Double> trimmedSmpl = new TreeMap<Double, Double> ();
		trimmedSmpl.putAll(smpl);
		Double range = trimmedSmpl.lastKey() - trimmedSmpl.firstKey();
		Double min = trimmedSmpl.firstKey() + range*p;
		Double max = trimmedSmpl.lastKey() - range*p;
		
		
		
		for (Double u : smpl.keySet()) {
			if ((u < min)||(u > max))
				trimmedSmpl.remove(u);
			
		}
		return trimmedSmpl;
	}
	
	public void analyzeData(String fileName) throws FileNotFoundException {
		ProbDistribution distX = new UniformDistribution(0.0, 6.0);
//		ProbDistribution distX = new ExpDistribution(1/Math.sqrt(3.0));
		ProbDistribution distEps = new NormalDistribution(0.0,0.5);
		ProbDistribution distXi = new NormalDistribution(0.0,0.5);
		int n = 100;
		double b0 = 0.5;
		double b1 = 1.0;
		
		List<Double> X = distX.getSample(n);
		List<Double> Eps = distEps.getSample(n);
		List<Double> Xi = distXi.getSample(n);
		
		List<Double> Y = new ArrayList<Double> ();
		for (Double x : X) {
			Y.add(b0+b1*x);
		}
		
		PrintWriter out = new PrintWriter (new FileOutputStream(fileName));
		out.println("X,Y,Eps,Xi");
		for (int i=0; i<n; i++) {
			out.println(X.get(i)+","+Y.get(i)+","+Eps.get(i)+","+Xi.get(i));
		}
		out.flush();
		out.close();
		
	}
	
	private Map<Double, Double> getFun (ProbDistribution distX, ProbDistribution distEps,
			ProbDistribution distXi, int n, int m, boolean repeatable) {
		double b0 = 0.5;
		double b1 = 1.0;
		
		Map<Double, Double> B = new TreeMap<Double, Double> ();
		Map<Double, Double> A = new TreeMap<Double, Double> ();
		
		for (int i = 0; i < m; i++) {
			//Generate data
			List<Double> X = (repeatable) ? distX.getSample(n,r) : distX.getSample(n);
			List<Double> Eps = (repeatable) ? distEps.getSample(n,r) : distEps.getSample(n);
			List<Double> Xi = (repeatable) ? distXi.getSample(n,r) : distXi.getSample(n);
			
			Map<Double, Double> V = new TreeMap<Double, Double> ();
			for (int j = 0; j < n; j++) {
				V.put(X.get(j)+Xi.get(j), b0+b1*X.get(j)+Eps.get(j));
			}
			

			double p = 0.0;
			while (p < 0.35001) {
				if (B.get(p) == null) {
					B.put(p, 0.0);
				}
				if (A.get(p) == null) {
					A.put(p, 0.0);
				}
				Map<Double, Double> trV = trimSample(V, p);
				
				
				Map<Double, Double> normV = MathCommon.Normalize(trV);

				Double b11 = new LeastSquareMethod().estimate(new ArrayList<Double> (normV.values()), 
						new ArrayList<Double>(normV.keySet()));
				Double b01 = MathCommon.getMean(new ArrayList<Double>(trV.values())) - 
						b11*MathCommon.getMean(new ArrayList<Double>(trV.keySet()));
				
				B.put(p, B.get(p) + (double) b11/(b1*m));
				A.put(p, A.get(p) + (double) b01/(b0*m));
				p += 0.025;
			}
		}
		return B;
	}
	
	public void doWork2 (String fileName) throws FileNotFoundException {
		
		boolean repeatable = true;
		r = new Random(100);
		
		ProbDistribution distEps = new NormalDistribution(0.0,0.5);
		ProbDistribution distXi = new NormalDistribution(0.0,0.5);
		int n = 100;
		int m = 1000;
		
		ProbDistribution distX = new ExpDistribution(1/Math.sqrt(3.0));
		Map<Double, Double> B_Exp = getFun(distX, distEps, distXi, n, m, repeatable);
		
		distX = new UniformDistribution(0.0, 6.0);
		Map<Double, Double> B_Un = getFun(distX, distEps, distXi, n, m, repeatable);
		
		distX = new LNormalDistribution(-Math.log(4)/2.0, Math.log(4));
		Map<Double, Double> B_LN = getFun(distX, distEps, distXi, n, m, repeatable);
		
		distX = new LaplasDistribution(Math.sqrt(2.0/3.0), 5.0);
		Map<Double, Double> B_L = getFun(distX, distEps, distXi, n, m, repeatable);
		
		PrintWriter out = new PrintWriter (new FileOutputStream(fileName));
		out.println("p, b_Exp, b_Un, b_LN, B_L");
		for (Double p : B_Exp.keySet()) {
			out.println(p+","+B_Exp.get(p)+","+B_Un.get(p)+","+B_LN.get(p)
					+","+B_L.get(p));
		}
		out.flush();
		out.close();
		
	}
	
	public static void main (String[] args) throws FileNotFoundException {
		SampleTrimming st = new SampleTrimming();
//		st.doWork2("B(p)sxi_1.csv");
		st.analyzeData("Unif_data.csv");
		
		
	}
	

}
